package com.dc.chat.websocket.controller;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.dc.chat.app.service.mp.*;
import com.dc.chat.entity.dao.*;
import com.dc.chat.entity.redisCatch.LoginUser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
//    https://blog.csdn.net/yingxiake/article/details/51213060

/**
 而方法参数的返回值会被MessageConverter进行转化封装然后发送给广播出去，类似springmvc的方法中带@responsebody注解时候方法返回值会被httpMessageConverter进行转化一样。

 spring websocket的方法参数中还允许有其他一些参数如下

 Principal principal ,存放用户的登录验证信息
 Message message，最基础的消息体，里面方有header和payload等信息
 @Payload 消息体内容
 @Header(“..”) 某个头部key的值
 @Headers, 所有头部key的map集合
 MessageHeaders , SimpMessageHeaderAccessor, MessageHeaderAccessor ,StompHeaderAccessor 消息头信息
 @DestinationVariable 类似springmvc中的@PathVariable
 ————————————————
 版权声明：本文为CSDN博主「node2017」的原创文章，遵循CC 4.0 BY-SA版权协议，转载请附上原文出处链接及本声明。
 原文链接：https://blog.csdn.net/yingxiake/article/details/51213060
 */
//    {contextType:1,context:m.value}
@Controller
public class MessageController {
    @Resource
    SimpMessagingTemplate simpMessagingTemplate;
    @Autowired
    RedisTemplate redisTemplate;
    @Autowired
    CommonMessageService commonMessageService;
    @Resource
    UserService.UserMapper userMapper;
    @Resource
    FriendService friendService;
    @Resource
    UserService userService;
    @Resource
    FriendMessageService friendMessageService;
    @Resource
    GrpDetailService.GrpDetailMapper grpDetailMapper;
    @Resource
    GrpMessageService.GrpMessageMapper grpMessageMapper;
    @Resource
    SensitiveService.SensitiveMapper sensitiveMapper;

    @MessageMapping("/q")
    @SendTo("/q")
    public String qunliao(String message, @Header("token") String token) throws JsonProcessingException {
        ObjectMapper objectMapper=new ObjectMapper();
        Map map = objectMapper.readValue(message, Map.class);
        Integer contextType = (Integer) map.get("contextType");
        String context = (String) map.get("context");
        if(contextType==1){
            List<Sensitive> sensitives = sensitiveMapper.selectList(Wrappers.lambdaQuery(new Sensitive() ).eq(Sensitive::getType, 1));
            Set<String> badwords = sensitives.stream().map(i -> i.getContent()).collect(Collectors.toSet());
            for (String badword : badwords) {
                StringBuilder stringBuilder=new StringBuilder("");
                int length = badword.length();
                for (int i=0;i<length;i++){
                    stringBuilder.append("*");
                }
                context=context.replace(badword,stringBuilder.toString());
            }
        }

        Jws<Claims> jws = Jwts.parser().setSigningKey("abcdef").parseClaimsJws(token);
        Claims body = jws.getBody();
        String username = (String) body.get("username");
        String key="login#1#"+username+"#"+token;
        LoginUser loginUser = (LoginUser) redisTemplate.opsForValue().get(key);
        CommonMessage commonMessage=new CommonMessage();
        commonMessage.setCreateTime(LocalDateTime.now());
        commonMessage.setContext(context);
        commonMessage.setContextType(contextType);
        commonMessage.setDeleted(0);
        commonMessage.setFromUserAvatar(loginUser.getAvatar());
        commonMessage.setFromUserId(loginUser.getId());
        commonMessage.setFromUserName(loginUser.getUsername());
        commonMessageService.save(commonMessage);
        //通知管理员 刷新群聊
        Set<String> adminTokens = redisTemplate.opsForSet().members("admin");
        Map map1=new HashMap();
        map1.put("refreshCommonMessage",true);
        for (String adminToken : adminTokens) {
            simpMessagingTemplate.convertAndSend("/back/"+adminToken,"",map1);
        }
        return objectMapper.writeValueAsString(commonMessage);
    }
    @Transactional
    @MessageMapping("/u")
    public void siliao(String message, @Header("token") String token,@Header(value = "to",required = false) Integer id) throws JsonProcessingException {
        ObjectMapper objectMapper=new ObjectMapper();
        Map map = objectMapper.readValue(message, Map.class);



        Integer contextType = (Integer) map.get("contextType");
        String context = (String) map.get("context");


        if(contextType==1){
            List<Sensitive> sensitives = sensitiveMapper.selectList(Wrappers.lambdaQuery(new Sensitive()).eq(Sensitive::getType, 1));
            Set<String> badwords = sensitives.stream().map(i -> i.getContent()).collect(Collectors.toSet());
            for (String badword : badwords) {
                StringBuilder stringBuilder=new StringBuilder("");
                int length = badword.length();
                for (int i=0;i<length;i++){
                    stringBuilder.append("*");
                }
                context=context.replace(badword,stringBuilder.toString());
            }
        }

        Jws<Claims> jws = Jwts.parser().setSigningKey("abcdef").parseClaimsJws(token);
        Claims body = jws.getBody();
        String username = (String) body.get("username");
        String key="login#1#"+username+"#"+token;
        LoginUser loginUser = (LoginUser) redisTemplate.opsForValue().get(key);

        //判断群聊单聊
        Integer ql = (Integer) map.get("ql");
        if(ql!=null){
            GrpDetail grpDetail = grpDetailMapper.selectOne(Wrappers.lambdaQuery(new GrpDetail()).eq(GrpDetail::getGrpId, ql).eq(GrpDetail::getUserId, loginUser.getId()));
            if(grpDetail==null){
                throw new RuntimeException("不在群里怎么发信息");
            }
            GrpMessage grpMessage=new GrpMessage();
            grpMessage.setGrpId(ql);
            grpMessage.setContext(context);
            grpMessage.setContextType(contextType);
            grpMessage.setCreateTime(LocalDateTime.now());
            User user = userService.selectByUserName(loginUser.getUsername());
            grpMessage.setFromUserAvatar(user.getAvatar());
            grpMessage.setFromUserId(user.getId());
            grpMessage.setFromUserName(user.getUserName());
            grpMessageMapper.insert(grpMessage);
            //推送消息
            //群组中所有用户
            List<GrpDetail> grpDetails = grpDetailMapper.selectList(Wrappers.lambdaQuery(new GrpDetail()).eq(GrpDetail::getGrpId, ql));
            Set<Integer> grpUserIds = grpDetails.stream().map(i -> i.getUserId()).collect(Collectors.toSet());
            List<User> users = userMapper.selectBatchIds(grpUserIds);
            List<String> grpUserNames = users.stream().map(i -> i.getUserName()).collect(Collectors.toList());
            //所有在线用户
            Map<String,String> userTokenMap = redisTemplate.opsForHash().entries("login");
            if(!userTokenMap.isEmpty()){
                for (String un : grpUserNames) {
                    if (!userTokenMap.keySet().contains(un)) {
                        //不在线的
                        User user1 = userMapper.selectOne(Wrappers.lambdaQuery(new User()).eq(User::getUserName, un));
                        GrpDetail grpDetail1 = grpDetailMapper.selectOne(Wrappers.lambdaQuery(new GrpDetail()).eq(GrpDetail::getGrpId, ql).eq(GrpDetail::getUserId, user1.getId()));
                            grpDetail1.setNoRead(grpDetail.getNoRead() + 1);
                            grpDetailMapper.updateById(grpDetail1);
                    }else{
                        //在线的
                        String token1 = userTokenMap.get(un);
                        Jws<Claims> jws1 = Jwts.parser().setSigningKey("abcdef").parseClaimsJws(token1);
                        Claims body1 = jws1.getBody();
                        String username1 = (String) body1.get("username");
                        String key1="login#1#"+username1+"#"+token1;
                        LoginUser loginUser1 = (LoginUser) redisTemplate.opsForValue().get(key1);
                        if (!ql.equals(loginUser1.getActiveGrpId())) {
                            //在线没选中 该群的
                            User user1 = userMapper.selectOne(Wrappers.lambdaQuery(new User()).eq(User::getUserName, un));
                            GrpDetail grpDetail1 = grpDetailMapper.selectOne(Wrappers.lambdaQuery(new GrpDetail()).eq(GrpDetail::getGrpId, ql).eq(GrpDetail::getUserId, user1.getId()));
                            grpDetail1.setNoRead(grpDetail.getNoRead() + 1);
                            grpDetailMapper.updateById(grpDetail1);
                        }
                        //推送群消息
                        Map map1=new HashMap();
                        map1.put("grpMessage",true);
                        simpMessagingTemplate.convertAndSend("/u/"+userTokenMap.get(un),objectMapper.writeValueAsString(grpMessage),map1);
                    }
                }
            }else{
                for (Integer grpUserId : grpUserIds) {
                    GrpDetail grpDetail1 = grpDetailMapper.selectOne(Wrappers.lambdaQuery(new GrpDetail()).eq(GrpDetail::getGrpId, ql).eq(GrpDetail::getUserId, grpUserId));
                    grpDetail1.setNoRead(grpDetail.getNoRead()+1);
                    grpDetailMapper.updateById(grpDetail1);
                }
            }

            return;
        }


        //检查是不是好友
        boolean check = friendService.check(loginUser.getId(), id);
        if(!check){
            throw new  RuntimeException("俩人不是好友 发什么消息");
        }

        FriendMessage friendMessage=new FriendMessage();
        friendMessage.setFromUserId(loginUser.getId());
        friendMessage.setToUserId(id);
        friendMessage.setContext(context);
        friendMessage.setContextType(contextType);
        friendMessage.setCreateTime(LocalDateTime.now());
        User fromUser = userService.getById(loginUser.getId());
        friendMessage.setFromUserAvatar(fromUser.getAvatar());
        User toUser = userService.getById(id);
        friendMessage.setToUserAvatar(toUser.getAvatar());
        friendMessageService.save(friendMessage);
        //LocalDataTime objectmapper 转换出错
        simpMessagingTemplate.convertAndSend("/u/"+token,objectMapper.writeValueAsString(friendMessage));
        String toToken = (String) redisTemplate.opsForHash().get("login", toUser.getUserName());
        simpMessagingTemplate.convertAndSend("/u/"+toToken,objectMapper.writeValueAsString(friendMessage));

        Map userTokenMap = redisTemplate.opsForHash().entries("login");
        Set<String> set = userTokenMap.keySet();
        if(set.contains(toUser.getUserName())){
            LoginUser loginUser1 = (LoginUser) redisTemplate.opsForValue().get("login#1#" + toUser.getUserName() + "#" + userTokenMap.get(toUser.getUserName()));
            Integer activeUserId = loginUser1.getActiveUserId();
            if(fromUser.getId().equals(activeUserId)){
                //好友在线 从redis中读取activeUserId 如果是自己就不更新数据库未读消息
            }else{
                //不是自己就更新数据库未读消息
                Friend friend = friendService.getOne(Wrappers.lambdaQuery(new Friend()).eq(Friend::getUserId, toUser.getId()).eq(Friend::getFriendId, fromUser.getId()));
                friend.setNoRead(friend.getNoRead()+1);
                friendService.updateById(friend);
            }

        }else{
            //好友不在线就直接更新未读消息
            Friend friend = friendService.getOne(Wrappers.lambdaQuery(new Friend()).eq(Friend::getUserId, toUser.getId()).eq(Friend::getFriendId, fromUser.getId()));
            friend.setNoRead(friend.getNoRead()+1);
            friendService.updateById(friend);
        }

    }
}
